package pl.elka.pszt.model.argument;

/**
 * Reprezentuje argument literalu.
 * 
 * @author Andrzej Makarewicz
 * 
 */
public abstract class Argument {
	
	public enum Type {
		CONSTANT, VARIABLE
	}
	
	private final int id;
	private final Type type;
	private final ArgumentHelper helper;
	
	/**
	 * Zwraca opowiednia klase argumentu w zaleznosci od typu
	 * @param id
	 * @param type
	 * @param helper
	 * @return
	 */
	public static Argument createArgument(int id, Type type, ArgumentHelper helper) {
		if (type == null || helper == null) throw new NullPointerException();
		
		switch (type) {
		case CONSTANT:
			return new Constant(id, helper);
		case VARIABLE:
			return new Variable(id, helper);
		default:
			throw new IllegalArgumentException();
		}
	}
	
	public Argument(int id, Type type, ArgumentHelper helper) {
		if (type == null || helper == null) throw new NullPointerException();
		
		this.id = id;
		this.type = type;
		this.helper = helper;
	}
	
	public int getId() {
		return id;
	}
	
	public Type getType() {
		return type;
	}
	
	public boolean isConstant() {
		return type == Type.CONSTANT;
	}
	
	public boolean isVariable() {
		return type == Type.VARIABLE;
	}
	
	@Override
	public String toString() {
		return helper.getArgumentName(this);
	}
	
	@Override
	public int hashCode() {
		return 31 + id;
	}
	
	@Override
	public boolean equals(Object obj) {
		if (this == obj) return true;
		if (obj == null) return false;
		if (getClass() != obj.getClass()) return false;
		Argument other = (Argument) obj;
		if (id != other.id) return false;
		if (type != other.type) return false;
		return true;
	}
	
	/**
	 * 
	 * @param other
	 * @return czy mozliwe jest podstawienie pod ten argument
	 */
	public boolean matches(Argument other) {
		if (isVariable() || equals(other)) return true;
		
		return false;
	}
	
}
